package no.ntnu.fp.gui.calendar;
import java.awt.Dimension;
import java.util.Calendar;
import java.util.GregorianCalendar;

import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;

import no.ntnu.fp.gui.mainFrame.MainFrame.CalendarWidgetWeekChangeEvent;
import no.ntnu.fp.gui.mainFrame.MainFrame.CalendarWidgetWeekChangeListener;


@SuppressWarnings("serial")
public class CalendarWidget extends JPanel { // implements PropertyChangeListener{
	private final static String[] tableHeaders = {"Uke", "Man", "Tir", 
		"Ons", "Tor", "Fre", "Lør", "Søn"};
	private JTable table;
	private JScrollPane scroll;
	private Calendar calendar;
//	private int month, year;
	
	private CalendarWidgetWeekChangeListener weekChangeListener;
	
	private final MyListListener myListListener = new MyListListener();
	
	private final MyTableModel dataModel;
	
	public CalendarWidget(Calendar calendar){
		this.calendar = calendar;
//		calendar.setFirstDayOfWeek(Calendar.MONDAY);
//		calendar.setLenient(true);
//		this.month = month;
//		this.year = year;
		dataModel = new MyTableModel();
		dataModel.updateCalendar();
		table = new JTable(dataModel);
		table.getTableHeader().setReorderingAllowed(false);
		table.setShowGrid(false);
		table.setRowSelectionAllowed(true);
		table.setColumnSelectionAllowed(false);
		table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		table.setPreferredScrollableViewportSize(new Dimension(250, 98));
		table.setFillsViewportHeight(true);

		ListSelectionModel list = table.getSelectionModel();
		list.addListSelectionListener(myListListener);
		
//		Always in current month when initializing
//		if(calendar.get(Calendar.MONTH) != month){
//			table.setRowSelectionInterval(0, 0);
//		}else{
//			table.setRowSelectionInterval(calendar.get(Calendar.WEEK_OF_MONTH)
//					- calendar.getActualMinimum(Calendar.WEEK_OF_MONTH), 
//					calendar.get(Calendar.WEEK_OF_MONTH)
//					- calendar.getActualMinimum(Calendar.WEEK_OF_MONTH));
//		}
		
		selectCurrentWeekInTable();

		scroll = new JScrollPane(table);
		this.add(scroll);
	}
	
	class MyTableModel extends AbstractTableModel {
		
		private Calendar calendar;
		
		public void updateCalendar() {
			this.calendar = (Calendar)CalendarWidget.this.calendar.clone();
		}

		public int getColumnCount() { return 8; }
		public int getRowCount() { return 6 
						- calendar.getActualMinimum(GregorianCalendar.WEEK_OF_MONTH);}
		public boolean isCellEditable(int row, int col){ return false; }
		public Object getValueAt(int row, int col) {
			calendar.clear(GregorianCalendar.YEAR);
			calendar.clear(GregorianCalendar.MONTH);
			calendar.clear(GregorianCalendar.WEEK_OF_MONTH);
			calendar.clear(GregorianCalendar.DAY_OF_WEEK);

			calendar.set(GregorianCalendar.YEAR, getYear());
			calendar.set(GregorianCalendar.MONTH, getMonth());
			
			calendar.set(GregorianCalendar.DAY_OF_WEEK, col + 1);
			calendar.set(GregorianCalendar.WEEK_OF_MONTH,
					row + calendar.getActualMinimum(Calendar.WEEK_OF_MONTH));
			calendar.set(GregorianCalendar.DAY_OF_WEEK, col + 1);

			if(col == 0){
				int week = calendar.get(GregorianCalendar.WEEK_OF_YEAR);
				return week == 0 ? 52 : week;
			}else if(calendar.get(GregorianCalendar.MONTH) != getMonth()){
				return "";
			}else{				
				return (calendar.get(GregorianCalendar.DATE) < 10)? 
						"0" + calendar.get(GregorianCalendar.DATE) : 
							calendar.get(GregorianCalendar.DATE);
			}			
		}
		public String getColumnName(int col){
			return tableHeaders[col];
		}
	};
	
	public void setTableListener(CalendarWidgetWeekChangeListener listener){
		this.weekChangeListener = listener;

		
//		table.setSelectionModel(list);
	}
	
//	public int[] getWeekAndYear(){
//		calendar.set(Calendar.YEAR, year);
//		calendar.set(Calendar.MONTH, month);
//		calendar.set(Calendar.WEEK_OF_MONTH, table.getSelectedRow() 
//				+ calendar.getActualMinimum(Calendar.WEEK_OF_MONTH));
//		
//		return new int[] { 
//				calendar.get(Calendar.WEEK_OF_YEAR),
//				calendar.get(Calendar.YEAR)
//		};
//	}
//	
	public void updateDate() {
		/*
		 * end-of-year is not correctly handled! 
		 */
//		calendar.clear();
//		calendar.set(Calendar.YEAR, year);
////		calendar.set(Calendar.DAY_OF_, 1);
//		calendar.set(Calendar.WEEK_OF_YEAR, week);
//		this.month = calendar.get(Calendar.MONTH);
//		this.year = calendar.get(Calendar.YEAR);
		
		dataModel.updateCalendar();
		table.repaint();
		selectCurrentWeekInTable();
	}

//	@Override
//	public void propertyChange(PropertyChangeEvent evt) {
//		if(evt.getPropertyName() == SelectMonthPanel.MONTH_PROPERTY){
//			month = (Integer) evt.getNewValue();
//		}else if(evt.getPropertyName() == SelectMonthPanel.YEAR_PROPERTY){
//			year = (Integer) evt.getNewValue();
//		}else{
//			throw new UnsupportedOperationException("Not implemented");
//		}
//		int week = calendar.get(Calendar.WEEK_OF_MONTH)
//					- calendar.getActualMinimum(Calendar.WEEK_OF_MONTH);
//		table.repaint();		
//		final ListSelectionEvent listSelectionEvent 
//							= new ListSelectionEvent(table, week, week, false);
//		for (ListSelectionListener listener: listeners) {
//			listener.valueChanged(listSelectionEvent);
//		}
//	}
//	
	private void selectCurrentWeekInTable() {
		int currentWeekRow = calendar.get(Calendar.WEEK_OF_MONTH) 
						   - calendar.getActualMinimum(Calendar.WEEK_OF_MONTH);
		myListListener.warnAboutArtificialUpdate();
		table.setRowSelectionInterval(currentWeekRow, currentWeekRow);
	}
	
	private int getMonth() {
		return calendar.get(Calendar.MONTH);
	}
	
	private int getYear() {
		return calendar.get(Calendar.YEAR);
	}
	
	private final class MyListListener implements ListSelectionListener {
		private boolean artificialUpdate = false;
		
		public void warnAboutArtificialUpdate() {
			artificialUpdate = true;
		}

		@Override
		public void valueChanged(ListSelectionEvent e) {
			if (artificialUpdate) {
				artificialUpdate = false;
				return;
			}
			int weekOfMonth = table.getSelectedRow() 
							+ calendar.getActualMinimum(Calendar.WEEK_OF_MONTH);
			
			CalendarWidgetWeekChangeEvent evt 
			= new CalendarWidgetWeekChangeEvent(CalendarWidget.this, weekOfMonth);
			
			weekChangeListener.weekChanged(evt);
		}
	}
}
